package byx.container.extension.aop;

import byx.aop.ByxAOP;
import byx.container.annotation.extension.core.AnnotationMetadata;
import byx.container.annotation.extension.core.ClassPostProcessor;
import byx.container.annotation.extension.core.ClassPostProcessorContext;
import byx.container.core.RegisterInfo;
import byx.container.annotation.annotation.Order;
import byx.container.core.Container;
import byx.container.core.ObjectFactory;
import byx.container.extension.aop.annotation.Enhance;
import byx.container.extension.aop.annotation.Proxy;
import byx.util.proxy.ProxyType;

import java.util.List;

@Order(100)
public class ByxAopProcessor implements ClassPostProcessor {
    @Override
    public ObjectFactory<?> postProcess(ClassPostProcessorContext ctx) {
        RegisterInfo registerInfo = ctx.getRegisterInfo();
        ObjectFactory<?> factory = registerInfo.getFactory();
        Class<?> type = registerInfo.getType();

        if (type == AdviceManager.class || type.isAnnotationPresent(Enhance.class)) {
            return factory;
        }

        Container container = ctx.getContainer();
        ProxyType proxyType = getProxyType(ctx.getAnnotationMetadata());

        return new ObjectFactory<>() {
            @Override
            public Object create() {
                Object obj = factory.create();
                AdviceManager adviceManager = container.getObject(AdviceManager.class);
                List<Object> advices = adviceManager.getAdvices(obj.getClass());
                if (!advices.isEmpty()) {
                    return ByxAOP.getAopProxy(obj, proxyType, advices.toArray());
                }
                return obj;
            }

            @Override
            public String toString() {
                return String.format("%s.aop()", factory);
            }
        };
    }

    private ProxyType getProxyType(AnnotationMetadata annotationMetadata) {
        if (!annotationMetadata.isAnnotationPresent(Proxy.class)) {
            return ProxyType.AUTO;
        }
        return annotationMetadata.getAnnotation(Proxy.class).value();
    }
}
